(function($, undefined) {
	/*
	 * HoverDir object.
	 */
	$.HoverDir = function(options, element) {
		this.$el = $(element);
		this._init(options);
	};

	$.HoverDir.defaults = {
		hoverDelay: 0,
		reverse: false
	};

	$.HoverDir.prototype = {
		_init: function(options) {
			this.options = $.extend(true, {}, $.HoverDir.defaults, options);

			// load the events
			this._loadEvents();

		},
		_loadEvents: function() {
			var _self = this;
			this.$el.on('mouseenter.hoverdir, mouseleave.hoverdir', function(event) {
				var $el = $(this),
				evType = event.type,
				$hoverElem = $el.find('div'),
				direction = _self._getDir($el, {
					x: event.pageX,
					y: event.pageY
				}),
				hoverClasses = _self._getClasses(direction);
				$hoverElem.removeClass();
				if (evType === 'mouseenter') {
					$hoverElem.hide().addClass(hoverClasses.from);
					clearTimeout(_self.tmhover);
					_self.tmhover = setTimeout(function() {
						$hoverElem.show(0, function() {
							$(this).addClass('da-animate').addClass(hoverClasses.to);
						});
					}, _self.options.hoverDelay);
				} else {
					$hoverElem.addClass('da-animate');
					clearTimeout(_self.tmhover);
					$hoverElem.addClass(hoverClasses.from);
				}
			});
		},
		// credits : http://stackoverflow.com/a/3647634
		_getDir: function($el, coordinates) {
			/** the width and height of the current div **/
			var w = $el.width(),
				h = $el.height(),

				/** calculate the x and y to get an angle to the center of the div from that x and y. **/
				/** gets the x value relative to the center of the DIV and "normalize" it **/
				x = (coordinates.x - $el.offset().left - (w / 2)) * (w > h ? (h / w) : 1),
				y = (coordinates.y - $el.offset().top - (h / 2)) * (h > w ? (w / h) : 1),

				/** the angle and the direction from where the mouse came in/went out clockwise (TRBL=0123);**/
				/** first calculate the angle of the point, 
				add 180 deg to get rid of the negative values
				divide by 90 to get the quadrant
				add 3 and do a modulo by 4  to shift the quadrants to a proper clockwise TRBL (top/right/bottom/left) **/
				direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180) / 90) + 3) % 4;
			return direction;
		},
		_getClasses: function(direction) {
			var fromClass, toClass;
			switch (direction) {
				case 0: // from top
					(!this.options.reverse) ? fromClass = 'da-slideFromTop': fromClass = 'da-slideFromBottom';
					toClass = 'da-slideTop'; break;
				case 1: // from right
					(!this.options.reverse) ? fromClass = 'da-slideFromRight': fromClass = 'da-slideFromLeft';
					toClass = 'da-slideLeft'; break;
				case 2: // from bottom
					(!this.options.reverse) ? fromClass = 'da-slideFromBottom': fromClass = 'da-slideFromTop';
					toClass = 'da-slideTop'; break;
				case 3: // from left
					(!this.options.reverse) ? fromClass = 'da-slideFromLeft': fromClass = 'da-slideFromRight';
					toClass = 'da-slideLeft'; break;
			};
			return {
				from: fromClass,
				to: toClass
			};
		}
	};

	var logError = function(message) {
		if (this.console) {
			console.error(message);
		}
	};

	$.fn.hoverdir = function(options) {
		if (typeof options === 'string') {
			var args = Array.prototype.slice.call(arguments, 1);
			this.each(function() {
				var instance = $.data(this, 'hoverdir');
				if (!instance) {
					logError("cannot call methods on hoverdir prior to initialization; " +
						"attempted to call method '" + options + "'");
					return;
				}
				if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {
					logError("no such method '" + options + "' for hoverdir instance");
					return;
				}
				instance[options].apply(instance, args);
			});

		} else {
			this.each(function() {
				var instance = $.data(this, 'hoverdir');
				if (!instance) {
					$.data(this, 'hoverdir', new $.HoverDir(options, this));
				}
			});

		}
		return this;
	};
})(jQuery);